package cn.react.compress;

import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Environment;
import android.provider.MediaStore;
import android.util.Log;

import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.bridge.WritableNativeMap;
import com.facebook.react.modules.core.DeviceEventManagerModule;

import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.UUID;

@SuppressWarnings("unused")
public class CompressModule extends ReactContextBaseJavaModule{
    private ReactApplicationContext reactContext;
    private DeviceEventManagerModule.RCTDeviceEventEmitter eventEmitter;
    private static CompressModule sModule =null;

    private ResultCollector resultCollector = new ResultCollector();
    CompressModule(ReactApplicationContext reactContext) {
        super(reactContext);
        this.onCreate(reactContext);
    }
    public void onCreate(ReactApplicationContext reactContext)
    {
        this.reactContext = reactContext;

    }
    @Override
    public String getName() {
        return "CompressHelper";
    }

    private BitmapFactory.Options validateImage(String path) throws Exception {
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        options.inPreferredConfig = Bitmap.Config.RGB_565;
        options.inDither = true;

        BitmapFactory.decodeFile(path, options);

        if (options.outMimeType == null || options.outWidth == 0 || options.outHeight == 0) {
            throw new Exception("Invalid image selected");
        }

        return options;
    }

    @ReactMethod
    public  void compress(final ReadableMap params, final Promise promise)
    {
        resultCollector.setup(promise, false);
        try {
            String originalImagePath = params.getString("path");
            int maxSize = params.getInt("limitSize");
            File resized = this._compress(originalImagePath,maxSize);
            Uri resultUri = Uri.fromFile(resized);
            String compressedImagePath = resized.getPath();
            BitmapFactory.Options options = this.validateImage(compressedImagePath);
            long modificationDate = new File(compressedImagePath).lastModified();
            WritableMap image = new WritableNativeMap();
            image.putString("path", "file://" + compressedImagePath);
            image.putInt("width", options.outWidth);
            image.putInt("height", options.outHeight);
            image.putString("mime", options.outMimeType);
            image.putInt("size", (int) new File(compressedImagePath).length());
            resultCollector.notifySuccess(image);
        }
        catch (IOException e)
        {

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private File _compress(String path,int maxSize) throws IOException {

        String realPath = path.replace("file://","");
        Bitmap original = BitmapFactory.decodeFile(realPath);

        int width = original.getWidth();
        int height = original.getHeight();
        float ratio = (float)(width)/(float)height;

        Bitmap resized = Bitmap.createScaledBitmap(original, 1080, (int)(1080/ratio), true);
        int maxLength =maxSize*1024;
        File imageDirectory = this.reactContext.getExternalFilesDir(Environment.DIRECTORY_PICTURES);
        if(!imageDirectory.exists()) {
            Log.d("image-crop-picker", "Pictures Directory is not existing. Will create this directory.");
            imageDirectory.mkdirs();
        }
        File resizeImageFile = new File(imageDirectory, UUID.randomUUID() + ".jpg");
        if(resized.getByteCount() < maxLength)
        {
            OutputStream os = new BufferedOutputStream(new FileOutputStream(resizeImageFile));
            resized.compress(Bitmap.CompressFormat.JPEG, 100, os);
            os.flush();
            os.close();
            original.recycle();
            return resizeImageFile;
        }
        float max = 1;
        float min = 0;
        float compression = 0;
        ByteArrayOutputStream baos =null;

        for(int i=0;i<10;++i)
        {
            compression = (max+min)/2;
            baos= new ByteArrayOutputStream();
            resized.compress(Bitmap.CompressFormat.JPEG,(int)(compression*100),baos);
            byte[] bytes = baos.toByteArray();
            if(bytes.length < maxLength*0.9)
            {
                min = compression;
            }
            else if(bytes.length > maxLength)
            {
                max = compression;
            }
            else
            {
                break;
            }
        }

        OutputStream os = new BufferedOutputStream(new FileOutputStream(resizeImageFile));
        resized.compress(Bitmap.CompressFormat.JPEG, (int)(compression*100), os);
        os.flush();
        os.close();
        original.recycle();
        return resizeImageFile;
    }
}
